package ascii

import (
	"container/list"
	"fmt"
	"log/slog"
	"math/big"
	"strconv"
	"strings"
)

var asciiSub []rune
var asciiMap map[int]int

func DoAsciiStringSplit(left string, right string, expectSliceNumber int) []string {
	//var radix = 128
	asciiSub, asciiMap = InitAsciiSub()
	var radix = 94

	tempResult := DoBigIntSplit(StringToBigInt(left, radix), StringToBigInt(right, radix), expectSliceNumber)
	var result []string
	//处理第一个字符串（因为：在转换为数字，再还原的时候，如果首字符刚好是 basic,则不知道应该添加多少个 basic）
	//result[0] = left
	//result[len(tempResult)-1] = right
	result = append(result, left)
	for i := 1; i < (len(tempResult) - 1); i++ {
		//result[i] = BigIntToString(tempResult[i], radix)
		result = append(result, BigIntToString(tempResult[i], radix))
	}
	result = append(result, right)
	return result
}

func DoLongSplit(left int64, right int64, expectSliceNumber int) []int64 {
	asciiSub, asciiMap = InitAsciiSub()
	result := DoBigIntSplit(big.NewInt(left), big.NewInt(right), expectSliceNumber)
	var returnResult []int64
	for i := 0; i < len(result); i++ {
		//returnResult[i] = result[i].Int64()
		returnResult = append(returnResult, result[i].Int64())
	}
	return returnResult
}

func DoBigIntSplit(left *big.Int, right *big.Int, expectSliceNumber int) []*big.Int {
	if expectSliceNumber < 1 {
		slog.Error("切分份数不能小于1. 此处:expectSliceNumber=[%s].", expectSliceNumber)
	}
	if nil == left || nil == right {
		slog.Error("对 BigInt 进行切分时，其左右区间不能为 null. 此处:left=[%s],right=[%s].", left, right)
	}
	if left.CmpAbs(right) == 0 {
		return []*big.Int{left, right}
	} else {
		// 调整大小顺序，确保 left < right
		if left.CmpAbs(right) > 0 {
			temp := left
			left = right
			right = temp
		}

		//left < right
		i := big.NewInt(1)
		endAndStartGap := i.Sub(right, left)
		ii := big.NewInt(1)
		step := ii.Div(endAndStartGap, big.NewInt(int64(expectSliceNumber)))
		iii := big.NewInt(1)
		remainder := iii.Rem(endAndStartGap, big.NewInt(int64(expectSliceNumber)))
		if step.CmpAbs(big.NewInt(0)) == 0 {
			expectSliceNumber = int(remainder.Int64())
		}
		//l := expectSliceNumber + 1
		var result []*big.Int
		result = append(result, left) // 添加元素到数组开头位置
		//result[0] = left
		//result[expectSliceNumber] = right
		var lowerBound *big.Int
		var upperBound *big.Int = left
		for i := 1; i < expectSliceNumber; i++ {
			lowerBound = upperBound
			iiii := big.NewInt(0)
			upperBound = iiii.Add(lowerBound, step)
			iiiii := big.NewInt(0)
			if remainder.CmpAbs(big.NewInt(int64(i))) >= 0 {
				upperBound = iiiii.Add(upperBound, big.NewInt(1))
			} else {
				upperBound = iiiii.Add(upperBound, big.NewInt(0))
			}
			//result[i] = upperBound
			result = append(result, upperBound)
		}
		result = append(result, right) // 最后一个元素
		return result
	}
}

func StringToBigInt(aString string, radix int) *big.Int {
	if aString == "" {
		slog.Error("")
	}
	checkIfBetweenRange(radix, 1, 94)
	result := big.NewInt(0)
	radixBigInt := big.NewInt(int64(radix))
	var tempChar int
	k := 0
	for i := len(aString) - 1; i >= 0; i-- {
		tempChar = int(aString[i])
		if tempChar > 128 {
			slog.Error("")
		}

		ii := big.NewInt(1)
		//x := new(big.Int).Exp(radixBigInt, big.NewInt(int64(k)), nil)
		//x := ii.Exp(radixBigInt, big.NewInt(int64(k)), nil)
		iii := big.NewInt(1)
		//iii.Mul(big.NewInt(int64(tempChar)), x)
		// 按94个字符的ASCII MAP转换后相加
		iii.Mul(big.NewInt(int64(asciiMap[tempChar])), ii.Exp(radixBigInt, big.NewInt(int64(k)), nil))
		result.Add(result, iii)
		k++
	}
	return result
}

func BigIntToString(bigInt *big.Int, radix int) string {
	if nil == bigInt {
		slog.Error("参数 bigInt 不能为空.")
	}
	checkIfBetweenRange(radix, 1, 94)

	var resultStringBuilder []rune
	var listStr list.List
	radixBigInt := big.NewInt(int64(radix))
	currentValue := bigInt
	var quotient *big.Int
	i := big.NewInt(1)
	quotient = i.Quo(currentValue, radixBigInt)

	for {
		//x := quotient.CmpAbs(big.NewInt(0))
		if quotient.CmpAbs(big.NewInt(0)) > 0 {
			ii := big.NewInt(1)
			listStr.PushFront(ii.Rem(currentValue, radixBigInt))
			iii := big.NewInt(1)
			currentValue = iii.Div(currentValue, radixBigInt)
			quotient = currentValue
		} else {
			break
		}
	}

	if listStr.Len() == 0 {
		ii := big.NewInt(1)
		listStr.PushBack(ii.Rem(currentValue, radixBigInt))
	}
	//var mapTmp map[int64]rune
	//mapTmp = make(map[int64]rune)
	//for i := 0; i < radix; i++ {
	//	mapTmp[int64(i)] = rune(i)
	//}
	for i := listStr.Front(); i != nil; i = i.Next() {
		//resultStringBuilder = append(resultStringBuilder, mapTmp[i.Value.(*big.Int).Int64()])
		resultStringBuilder = append(resultStringBuilder, asciiSub[i.Value.(*big.Int).Int64()])
	}
	return string(resultStringBuilder)
}

func checkIfBetweenRange(value int, left int, right int) {
	if value < left || value > right {
		slog.Error("parameter can not <[%s] or >[%s].", left, right)
	}
}

func quoteConstantValue(aString string, dataBaseType string) string {
	if "" == dataBaseType {
		return aString
	}
	if dataBaseType == "mysql" {
		//return aString.replace("'", "''").replace("\\", "\\\\")
		return strings.Replace(strings.Replace(aString, "'", "''", -1), "\\", "\\\\", -1)
	} else if dataBaseType == "oracle" {
		return strings.Replace(aString, "'", "''", -1)
	} else {
		return aString
	}
}

func WrapRangeStrArr(rangeResult []string, columnName string, quote string, dataBaseType string) list.List {
	if nil == rangeResult || len(rangeResult) < 2 {
		slog.Error("Parameter rangeResult can not be null and its length can not <2. detail:rangeResult=[%s].", strings.Join(rangeResult, ","))
	}
	var result list.List
	if len(rangeResult) == 2 {
		result.PushBack(fmt.Sprintf(" (%s%s%s <= %s%s%s AND %s%s%s <= %s%s%s) ", quote, quoteConstantValue(rangeResult[0], dataBaseType), quote, "`", columnName, "`", "`", columnName, "`", quote, quoteConstantValue(rangeResult[1], dataBaseType), quote))
		return result
	} else {
		for i := 0; i < len(rangeResult)-2; i++ {
			result.PushBack(fmt.Sprintf(" (%s%s%s <= %s%s%s AND %s%s%s < %s%s%s) ", quote, quoteConstantValue(rangeResult[i], dataBaseType), quote, "`", columnName, "`", "`", columnName, "`", quote, quoteConstantValue(rangeResult[i+1], dataBaseType), quote))
		}
		result.PushBack(fmt.Sprintf(" (%s%s%s <= %s%s%s AND %s%s%s <= %s%s%s) ", quote, quoteConstantValue(rangeResult[len(rangeResult)-2], dataBaseType), quote, "`", columnName, "`", "`", columnName, "`", quote, quoteConstantValue(rangeResult[len(rangeResult)-1], dataBaseType), quote))
		return result
	}
}

func WrapRangeBigIntArr(rangeResult []*big.Int, columnName string) list.List {
	var rangeStr []string
	for i := 0; i < len(rangeResult); i++ {
		//rangeStr[i] = rangeResult[i].String()
		rangeStr = append(rangeStr, rangeResult[i].String())
	}
	return WrapRangeStrArr(rangeStr, columnName, "", "")
}

func WrapRangeInt64Arr(rangeResult []int64, columnName string) list.List {
	var rangeStr []string
	for i := 0; i < len(rangeResult); i++ {
		//rangeStr[i] = strconv.FormatInt(rangeResult[i], 10)
		rangeStr = append(rangeStr, strconv.FormatInt(rangeResult[i], 10))
	}
	return WrapRangeStrArr(rangeStr, columnName, "", "")
}
